package com.example.flower_shop.service.impl;

import com.example.flower_shop.dto.review.ReviewDTO;
import com.example.flower_shop.dto.review.ReviewReplyDTO;
import com.example.flower_shop.entity.Review;
import com.example.flower_shop.entity.ReviewReply;
import com.example.flower_shop.entity.User;
import com.example.flower_shop.entity.Product;
import com.example.flower_shop.entity.ReviewLike;
import com.example.flower_shop.entity.CustomerOrder;
import com.example.flower_shop.exception.BusinessException;
import com.example.flower_shop.exception.ResourceNotFoundException;
import com.example.flower_shop.repository.ReviewRepository;
import com.example.flower_shop.repository.ReviewReplyRepository;
import com.example.flower_shop.repository.UserRepository;
import com.example.flower_shop.repository.ProductRepository;
import com.example.flower_shop.repository.ReviewLikeRepository;
import com.example.flower_shop.repository.CustomerOrderRepository;
import com.example.flower_shop.service.ReviewService;
import com.example.flower_shop.service.FileService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Optional;
import java.util.Map;
import java.util.HashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.context.SecurityContextHolder;
import org.modelmapper.ModelMapper;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class ReviewServiceImpl implements ReviewService {

    private final ReviewRepository reviewRepository;
    private final ReviewReplyRepository replyRepository;
    private final UserRepository userRepository;
    private final ProductRepository productRepository;
    private final FileService fileService;
    private final ReviewLikeRepository reviewLikeRepository;
    private final CustomerOrderRepository orderRepository;
    // private final ModelMapper modelMapper;

    private static final Logger log = LoggerFactory.getLogger(ReviewServiceImpl.class);

    @Override
    @Transactional
    public ReviewDTO createReview(Long userId, Long productId, ReviewDTO reviewDTO, List<MultipartFile> images) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new BusinessException("用户不存在"));

        Product product = productRepository.findById(productId)
                .orElseThrow(() -> new BusinessException("商品不存在"));

        // 检查订单号是否有效，已完成的订单才能评价
        String orderNo = reviewDTO.getOrderNo();
        if (orderNo == null || orderNo.isEmpty()) {
            throw new BusinessException("订单号不能为空");
        }

        // 检查用户是否已经评价过该订单中的该商品
        if (reviewRepository.existsByUserIdAndProductIdAndOrderNo(userId, productId, orderNo)) {
            throw new BusinessException("您已经评价过此订单中的该商品，不能重复评价");
        }

        // 检查订单是否存在且已完成
        // TODO: 使用OrderService查询订单并验证
        // 1. 订单属于当前用户
        // 2. 订单中包含当前商品
        // 3. 订单状态为"已完成"
        // 4. 用户尚未对此订单中此商品进行评价

        Review review = new Review();
        review.setUser(user);
        review.setProduct(product);
        review.setContent(reviewDTO.getContent());
        review.setRating(reviewDTO.getRating());
        review.setOrderNo(orderNo); // 设置订单号

        // 处理图片上传
        if (images != null && !images.isEmpty()) {
            log.info("处理上传的图片文件: {}", images.size());
            List<String> imageUrls = new ArrayList<>();
            for (MultipartFile image : images) {
                String imageUrl = fileService.uploadImage(image);
                imageUrls.add(imageUrl);
                log.info("上传图片成功: {}", imageUrl);
            }
            review.setImageUrls(imageUrls);
        }
        // 处理通过DTO传递的图片URL
        else if (reviewDTO.getImageUrls() != null && !reviewDTO.getImageUrls().isEmpty()) {
            log.info("处理通过DTO传递的图片URLs: {}", reviewDTO.getImageUrls());
            // 过滤掉空URL
            List<String> validUrls = reviewDTO.getImageUrls().stream()
                    .filter(url -> url != null && !url.trim().isEmpty())
                    .collect(Collectors.toList());

            if (!validUrls.isEmpty()) {
                log.info("设置评论图片URLs: {}", validUrls);
                review.setImageUrls(validUrls);
            } else {
                log.warn("过滤后没有有效的图片URL");
            }
        }

        log.info("保存评论: {}", review);
        review = reviewRepository.save(review);
        return new ReviewDTO(review);
    }

    @Override
    @Transactional
    public ReviewDTO updateReview(Long userId, Long reviewId, ReviewDTO reviewDTO, List<MultipartFile> images) {
        Review review = reviewRepository.findById(reviewId)
                .orElseThrow(() -> new BusinessException("评论不存在"));

        if (!review.getUser().getId().equals(userId)) {
            throw new BusinessException("无权修改此评论");
        }

        review.setContent(reviewDTO.getContent());
        review.setRating(reviewDTO.getRating());

        // 处理图片上传
        if (images != null && !images.isEmpty()) {
            List<String> imageUrls = new ArrayList<>();
            for (MultipartFile image : images) {
                String imageUrl = fileService.uploadImage(image);
                imageUrls.add(imageUrl);
            }
            review.setImageUrls(imageUrls);
        }

        review = reviewRepository.save(review);
        return new ReviewDTO(review);
    }

    @Override
    @Transactional
    public void deleteReview(Long userId, Long reviewId) {
        Review review = reviewRepository.findById(reviewId)
                .orElseThrow(() -> new BusinessException("评论不存在"));

        if (!review.getUser().getId().equals(userId)) {
            throw new BusinessException("无权删除此评论");
        }

        reviewRepository.delete(review);
    }

    @Override
    public Page<ReviewDTO> getProductReviews(Long productId, Pageable pageable) {
        log.info("获取商品评论列表, productId: {}, pageable: {}", productId, pageable);
        try {
            // 检查商品是否存在
            Product product = productRepository.findById(productId)
                    .orElseThrow(() -> new ResourceNotFoundException("商品", productId));

            // 获取评论列表
            Page<Review> reviews = reviewRepository.findByProductId(productId, pageable);
            log.info("获取商品评论成功, 共{}条评论", reviews.getTotalElements());

            // 转换为DTO
            Page<ReviewDTO> reviewDTOs = reviews.map(ReviewDTO::new);

            // 获取当前登录用户ID
            Long currentUserId = getCurrentUserId();

            // 如果用户已登录，设置点赞状态
            if (currentUserId != null) {
                setLikeStatus(reviewDTOs.getContent(), currentUserId);
            }

            return reviewDTOs;
        } catch (ResourceNotFoundException e) {
            log.error("获取商品评论失败: 商品不存在, productId: {}", productId);
            throw e;
        } catch (Exception e) {
            log.error("获取商品评论失败", e);
            throw new BusinessException("获取评论失败: " + e.getMessage());
        }
    }

    @Override
    public Page<com.example.flower_shop.dto.review.ReviewDTO> getReviewsByUserId(Long userId, Pageable pageable) {
        Page<Review> reviews = reviewRepository.findByUserIdOrderByCreateTimeDesc(userId, pageable);
        return reviews.map(review -> {
            com.example.flower_shop.dto.review.ReviewDTO dto = new com.example.flower_shop.dto.review.ReviewDTO(review);

            // 订单信息在当前ReviewDTO中无法设置，需要后续优化
            return dto;
        });
    }

    @Override
    public Page<com.example.flower_shop.dto.review.ReviewDTO> getUserReviews(Long userId, Pageable pageable) {
        // 直接调用getReviewsByUserId实现相同功能
        return getReviewsByUserId(userId, pageable);
    }

    @Override
    public Page<com.example.flower_shop.dto.review.ReviewDTO> getReviewsByProductId(Long productId, Pageable pageable) {
        // 直接调用getProductReviews实现相同功能
        return getProductReviews(productId, pageable);
    }

    @Override
    @Transactional
    public void createReview(Long userId, Long productId, String orderNo,
            com.example.flower_shop.dto.review.ReviewDTO reviewDTO) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new BusinessException("用户不存在"));

        Product product = productRepository.findById(productId)
                .orElseThrow(() -> new BusinessException("商品不存在"));

        // 检查订单号是否有效
        if (orderNo == null || orderNo.isEmpty()) {
            throw new BusinessException("订单号不能为空");
        }

        // 检查用户是否已经评价过该订单中的该商品
        if (reviewRepository.existsByUserIdAndProductIdAndOrderNo(userId, productId, orderNo)) {
            throw new BusinessException("您已经评价过此订单中的该商品，不能重复评价");
        }

        Review review = new Review();
        review.setUser(user);
        review.setProduct(product);
        review.setContent(reviewDTO.getContent());
        review.setRating(reviewDTO.getRating());
        review.setOrderNo(orderNo);

        // 处理图片
        if (reviewDTO.getImageUrls() != null && !reviewDTO.getImageUrls().isEmpty()) {
            review.setImageUrls(reviewDTO.getImageUrls());
        }

        reviewRepository.save(review);
    }

    @Override
    @Transactional
    public ReviewReplyDTO createReply(Long userId, Long reviewId, ReviewReplyDTO replyDTO) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new BusinessException("用户不存在"));

        Review parentReview = reviewRepository.findById(reviewId)
                .orElseThrow(() -> new BusinessException("评论不存在"));

        ReviewReply reply = new ReviewReply();
        reply.setUser(user);
        reply.setParentReview(parentReview);
        reply.setContent(replyDTO.getContent());

        reply = replyRepository.save(reply);
        return new ReviewReplyDTO(reply);
    }

    @Override
    @Transactional
    public ReviewReplyDTO updateReply(Long userId, Long replyId, ReviewReplyDTO replyDTO) {
        ReviewReply reply = replyRepository.findById(replyId)
                .orElseThrow(() -> new BusinessException("回复不存在"));

        if (!reply.getUser().getId().equals(userId)) {
            throw new BusinessException("无权修改此回复");
        }

        reply.setContent(replyDTO.getContent());
        reply = replyRepository.save(reply);
        return new ReviewReplyDTO(reply);
    }

    @Override
    @Transactional
    public void deleteReply(Long userId, Long replyId) {
        ReviewReply reply = replyRepository.findById(replyId)
                .orElseThrow(() -> new BusinessException("回复不存在"));

        if (!reply.getUser().getId().equals(userId)) {
            throw new BusinessException("无权删除此回复");
        }

        replyRepository.delete(reply);
    }

    @Override
    public Page<ReviewReplyDTO> getReviewReplies(Long reviewId, Pageable pageable) {
        Page<ReviewReply> replies = replyRepository.findByParentReviewId(reviewId, pageable);
        return replies.map(ReviewReplyDTO::new);
    }

    @Override
    @Transactional
    public void likeReview(Long userId, Long reviewId) {
        log.info("用户{}点赞评论{}", userId, reviewId);
        try {
            User user = userRepository.findById(userId)
                    .orElseThrow(() -> new BusinessException("用户不存在"));

            Review review = reviewRepository.findById(reviewId)
                    .orElseThrow(() -> new BusinessException("评论不存在"));

            // 检查是否已经点赞
            Optional<ReviewLike> existingLike = reviewLikeRepository.findByUserIdAndReviewId(userId, reviewId);
            if (existingLike.isPresent()) {
                log.info("用户{}已经点赞过评论{}", userId, reviewId);
                return;
            }

            // 创建点赞记录
            ReviewLike reviewLike = new ReviewLike();
            reviewLike.setUser(user);
            reviewLike.setReview(review);
            reviewLikeRepository.save(reviewLike);

            // 更新评论点赞数
            review.setLikesCount(review.getLikesCount() + 1);
            reviewRepository.save(review);
            log.info("用户{}点赞评论{}成功", userId, reviewId);
        } catch (Exception e) {
            log.error("点赞评论失败: {}", e.getMessage(), e);
            throw new BusinessException("点赞失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional
    public void unlikeReview(Long userId, Long reviewId) {
        log.info("用户{}取消点赞评论{}", userId, reviewId);
        try {
            Review review = reviewRepository.findById(reviewId)
                    .orElseThrow(() -> new BusinessException("评论不存在"));

            // 检查是否已经点赞
            Optional<ReviewLike> existingLike = reviewLikeRepository.findByUserIdAndReviewId(userId, reviewId);
            if (!existingLike.isPresent()) {
                log.info("用户{}未点赞过评论{}", userId, reviewId);
                return;
            }

            // 删除点赞记录
            reviewLikeRepository.delete(existingLike.get());

            // 更新评论点赞数
            int likesCount = Math.max(0, review.getLikesCount() - 1);
            review.setLikesCount(likesCount);
            reviewRepository.save(review);
            log.info("用户{}取消点赞评论{}成功", userId, reviewId);
        } catch (Exception e) {
            log.error("取消点赞评论失败: {}", e.getMessage(), e);
            throw new BusinessException("取消点赞失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional
    public void likeReply(Long userId, Long replyId) {
        // TODO: 实现评论回复点赞功能
        throw new BusinessException("功能尚未实现");
    }

    @Override
    @Transactional
    public void unlikeReply(Long userId, Long replyId) {
        // TODO: 实现评论回复取消点赞功能
        throw new BusinessException("功能尚未实现");
    }

    @Override
    public Long getProductReviewCount(Long productId) {
        return reviewRepository.countByProductId(productId);
    }

    @Override
    public Double getProductAverageRating(Long productId) {
        return reviewRepository.getAverageRatingByProductId(productId);
    }

    /**
     * 检查用户是否点赞了评论
     */
    public boolean checkUserLikedReview(Long userId, Long reviewId) {
        return reviewLikeRepository.findByUserIdAndReviewId(userId, reviewId).isPresent();
    }

    /**
     * 批量检查用户是否点赞了评论列表
     */
    public Map<Long, Boolean> checkUserLikedReviews(Long userId, List<Long> reviewIds) {
        List<ReviewLike> likes = reviewLikeRepository.findByUserIdAndReviewIdIn(userId, reviewIds);
        Map<Long, Boolean> likeStatusMap = new HashMap<>();

        // 初始化所有评论为未点赞
        reviewIds.forEach(id -> likeStatusMap.put(id, false));

        // 更新已点赞的评论状态
        likes.forEach(like -> likeStatusMap.put(like.getReview().getId(), true));

        return likeStatusMap;
    }

    /**
     * 设置评论的点赞状态
     */
    private void setLikeStatus(List<ReviewDTO> reviews, Long userId) {
        if (userId == null || reviews.isEmpty()) {
            return;
        }

        List<Long> reviewIds = reviews.stream()
                .map(ReviewDTO::getId)
                .collect(Collectors.toList());

        Map<Long, Boolean> likeStatusMap = checkUserLikedReviews(userId, reviewIds);

        reviews.forEach(review -> {
            Boolean isLiked = likeStatusMap.get(review.getId());
            if (isLiked != null) {
                review.setIsLiked(isLiked);
            }
        });
    }

    /**
     * 获取当前登录用户ID
     */
    private Long getCurrentUserId() {
        try {
            Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            if (principal instanceof Long) {
                return (Long) principal;
            }
            return null;
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public Page<ReviewDTO> getAllReviews(String keyword, Integer status, String date, Pageable pageable) {
        log.info("获取所有评论列表, keyword: {}, status: {}, date: {}", keyword, status, date);

        Page<Review> reviewsPage;

        // 根据条件筛选评论
        if (keyword != null && !keyword.trim().isEmpty()) {
            // 如果有关键词，搜索包含关键词的评论
            reviewsPage = reviewRepository.findByContentContaining(keyword, pageable);
        } else if (status != null) {
            // 如果指定了状态，按状态筛选
            reviewsPage = reviewRepository.findByStatus(status, pageable);
        } else if (date != null && !date.trim().isEmpty()) {
            // 如果指定了日期，按日期筛选
            try {
                java.time.LocalDate localDate = java.time.LocalDate.parse(date);
                java.time.LocalDateTime startOfDay = localDate.atStartOfDay();
                java.time.LocalDateTime endOfDay = localDate.atTime(23, 59, 59);

                reviewsPage = reviewRepository.findByCreateTimeBetween(startOfDay, endOfDay, pageable);
            } catch (Exception e) {
                log.error("日期格式错误: {}", date, e);
                // 如果日期格式错误，返回所有评论
                reviewsPage = reviewRepository.findAll(pageable);
            }
        } else {
            // 没有筛选条件，返回所有评论
            reviewsPage = reviewRepository.findAll(pageable);
        }

        // 转换为DTO并返回
        return reviewsPage.map(ReviewDTO::new);
    }

    @Override
    @Transactional
    public void deleteMerchantReview(Long reviewId) {
        log.info("商家删除违规评论, reviewId: {}", reviewId);

        Review review = reviewRepository.findById(reviewId)
                .orElseThrow(() -> new ResourceNotFoundException("评论不存在"));

        // 删除评论的所有回复
        replyRepository.deleteByReviewId(reviewId);

        // 删除评论的所有点赞
        reviewLikeRepository.deleteByReviewId(reviewId);

        // 删除评论
        reviewRepository.delete(review);

        log.info("商家删除违规评论成功, reviewId: {}", reviewId);
    }

    @Override
    @Transactional
    public void updateReviewStatus(Long reviewId, Integer status) {
        log.info("更新评论状态, reviewId: {}, status: {}", reviewId, status);

        Review review = reviewRepository.findById(reviewId)
                .orElseThrow(() -> new ResourceNotFoundException("评论不存在"));

        // 更新评论状态（0：隐藏，1：显示）
        review.setStatus(status);
        reviewRepository.save(review);

        log.info("更新评论状态成功, reviewId: {}", reviewId);
    }
}